/**
   \file  local_fn.hh
   \brief Adapters for locally defined function objects.

   When we use generic algorithms such as the ones provided by the STL,
   we often have to pass them callables (functions or function objects)
   that we define somewhat removed from the call site. Here is an
   illustrative example:

   \code

       static void do_something_complicated(const some_type& t)
       {
           // complicated processing of t
       }

       void some_class::some_func()
       {
           std::vector<some_type> v ;
           // build vector v and then:
           std::for_each(v.begin(), v.end(), do_something_complicated) ;
       }

   \endcode

   As we can see from the above example, the function that processes the
   elements of vector v is defined a little away from the place where it
   is actually used. In this instance, the distance between the call site
   and callable definition is not overly onerous w.r.t. code
   comprehensibility. However, in some situations, the functions or
   objects that process a container's elements may have quite a bit of
   other code between their definitions and the point at which they are
   actually used. This can result in code that is difficult to follow
   and, thus, maintain, extend, etc.

   In many situations, Boost.Lambda can help by allowing us to define
   small anonymous functions right where we need them. And although
   Boost.Lambda provides support for control structures, exception
   handling, etc., sometimes it might be better to simply define a
   separate callable instead of using Boost.Lambda.

   Nonetheless, we would still like to take advantage of the "locality of
   reference" that Boost.Lambda provides. That is, we would like to
   define our custom callable near the point where it is used.

   This file provides a generic API to achieve this. Thus, the example
   shown earlier may be rewritten as:

   \code

       void some_class::some_func()
       {
           class foo: public unary_fn<void, some_type> {
               void operator()(const some_type& t) {
                   // complicated processing of t
               }
           } do_something_complicated ;

           std::vector<some_type> v ;
           // build vector v and then:
           std::for_each(v.begin(), v.end(),
                         local_fn(do_something_complicated)) ;
       }

   \endcode

   Now we see that the complicated processing is defined right in the
   function where it is used so we don't have far to go when looking for
   the actions performed on vector v.

   Such locally defined function objects impose certain costs (virtual
   functions) and are not always appropriate. However, they can be quite
   useful in some cases.

   NOTE: This API is part of libgist. Ideally, we would like to see it
   become a part of Boost or some other such library or collection of
   libraries.
*/

/*
   This file is part of libgist.

   libgist is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2 of the License, or (at your
   option) any later version.

   libgist is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
   for more details.

   You should have received a copy of the GNU General Public License
   along with libgist; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/

/*
   REVISION HISTORY

   $HeadURL: http://libgist.googlecode.com/svn/branches/siagian_dev/src/local_fn.hh $
   $Id: local_fn.hh 78 2011-10-01 20:29:21Z libgist@gmail.com $
*/

#ifndef GIST_LOCAL_FUNCTION_DOT_H
#define GIST_LOCAL_FUNCTION_DOT_H

//------------------------------ HEADERS --------------------------------

// Standard C++
#include <functional>

//----------------------------- NAMESPACE -------------------------------

namespace gist {

//-------------------------- UNARY FUNCTIONS ----------------------------

/**
   \brief Base class for local unary function objects.

   When we use STL algorithms such as for_each and transform, we usually
   have to define functions or function objects to process the individual
   elements of the container or sequence of interest. The problem with
   this is that the logic for processing a data sequence, which is,
   arguably, the main point of many functions, is removed from the point
   where the data of interest is actually meant to be handled. That is,
   data processing becomes distributed across many different small
   functions and classes, hampering code readability and maintainability.

   Boost.Lambda ameliorates the situation in many cases when the
   processing is simple. However, sometimes we want to be able to do
   something fairly complicated, which often requires defining a separate
   function or object.

   This class helps in these cases by defining an interface for a unary
   function object. It is meant to be extended by local classes and used
   in conjunction with the local_unary_functor class like so:

   \code

       void some_function(const std::vector<some_type>& v)
       {
            struct something_complicated: public unary_fn<void, some_type> {
                void operator()(const some_type& t) const {
                    // do something complicated with t
                }
            } ;
            something_complicated func ;
            std::for_each(v.begin(), v.end(),
                          local_unary_functor<void, some_type>(func)) ;
       }

   \endcode

   Now, the complicated code to process the elements of the vector v is
   right in the function that does it instead of being defined somewhere
   else.
*/
template<typename ret, typename arg>
struct unary_fn: public std::unary_function<ret, arg> {
   virtual ret operator()(const arg&) const = 0 ;
} ;

/**
   \brief An adapter for local unary function objects.

   When we use STL algorithms such as for_each and transform, we usually
   have to define functions or function objects to process the individual
   elements of the container or sequence of interest. The problem with
   this is that the logic for processing a data sequence, which is,
   arguably, the main point of many functions, is removed from the point
   where the data of interest is actually meant to be handled. That is,
   data processing becomes distributed across many different small
   functions and classes, hampering code readability and maintainability.

   Boost.Lambda ameliorates the situation in many cases when the
   processing is simple. However, sometimes we want to be able to do
   something fairly complicated, which often requires defining a separate
   function or object.

   This class helps in these cases by defining a generic unary function
   object meant to be used in conjunction with the unary_fn class so that
   the code to process containers, etc., can be defined in local classes
   right near the call site of STL/generic algorithms. Here is some
   illustrative code showing how this class should be used:

   \code

       template<typename T>
       std::vector<T> some_function(const std::vector<T>& v)
       {
            struct transformer: public unary_fn<T, T> {
                T operator()(const T& t) const {
                    T new_t = complicated_transformation(t) ;
                    return new_t ;
                }
            } trans ;
            std::vector<T> vv ;
            vv.reserve(v.size()) ;
            std::transform(v.begin(), v.end(), std::back_inserter(vv),
                           local_unary_functor<T, T>(trans)) ;
            return vv ;
       }

   \endcode

   Now, the complicated code to process the elements of the vector v is
   right in the function that does it instead of being defined somewhere
   else.

   NOTE: One small point to keep in mind when using this adapter is that,
   since it holds a reference to a unary_fn object (so that the virtual
   function mechanism works properly and invokes the derived class's
   function call operator), you must create a local variable
   instantiating the local class derived from unary_fn. That is, you
   cannot create a temporary instance as is often done in conjunction
   with STL algorithms. In the above code, for example, you cannot use
   the following call to the transform algorithm:

   \code
       std::transform(v.begin(), v.end(), std::back_inserter(vv),
                      local_unary_functor<T, T>(transformer())) ;
   \endcode

   This doesn't work because the compiler can get rid of the temporary
   object at its discretion so that by the time the call to
   local_unary_functor's constructor kicks in, there is no object
   available of which we can take a reference. Thus, it is required to
   create a local variable of type transformer (trans in the above sample
   code).
*/
template<typename ret, typename arg>
class local_unary_functor {
   unary_fn<ret, arg>& f ;
public:
   local_unary_functor(unary_fn<ret, arg>& fn): f(fn) {}
   ret operator()(const arg& a) {return f(a) ;}
} ;

/**
   \brief  Helper function to return local unary function object adapters.
   \param  f Reference to a unary_fn derived object.
   \return A local_unary_functor adapter that can be passed to STL algorithms.

   This function simplifies the call site syntax associated with using
   the unary_fn and local_unary_functor classes by using template
   function parameter type deduction to reduce the amount of code needed
   to fully specify and utilize the local function object paradigm
   enabled by these classes.

   Thus, for instance, the sample code shown for the unary_fn class
   would become:

   \code

       void some_function(const std::vector<some_type>& v)
       {
            struct something_complicated: public unary_fn<void, some_type> {
                void operator()(const some_type& t) const {
                    // do something complicated with t
                }
            } ;
            something_complicated func ;
            std::for_each(v.begin(), v.end(), local_fn(func)) ;
       }

   \endcode

   As we can see, with this function we don't have to specify the
   template types when creating an instance of local_unary_functor to
   pass to the for_each algorithm.
*/
template<typename ret, typename arg>
inline local_unary_functor<ret, arg>
local_fn(unary_fn<ret, arg>& f)
{
   return local_unary_functor<ret, arg>(f) ;
}

//------------------------- BINARY FUNCTIONS ----------------------------

/**
   \brief Base class for local binary function objects.

   When we use STL algorithms such as for_each and transform, we usually
   have to define functions or function objects to process the individual
   elements of the container or sequence of interest. The problem with
   this is that the logic for processing a data sequence, which is,
   arguably, the main point of many functions, is removed from the point
   where the data of interest is actually meant to be handled. That is,
   data processing becomes distributed across many different small
   functions and classes, hampering code readability and maintainability.

   Boost.Lambda ameliorates the situation in many cases when the
   processing is simple. However, sometimes we want to be able to do
   something fairly complicated, which often requires defining a separate
   function or object.

   This class helps in these cases by defining an interface for a binary
   function object. It is meant to be extended by local classes and used
   in conjunction with the local_binary_functor class like so:

   \code

      std::vector<type3>
      some_function(const std::vector<type1>& v1, const std::vector<type2>& v2)
      {
         struct something_complicated: public binary_fn<type3, type1, type2> {
            type3 operator()(const type1& t1, const type2& t2) const {
               return something_complicated(t1, t2) ;
            }
         } func ;
         std::vector<type3> v3 ;
         std::transform(v1.begin(), v1.end(), v2.begin(),
                        std::back_inserter(v3),
                        local_binary_functor<type3, type1, type2>(func)) ;
         return v3 ;
      }

   \endcode

   Now, the complicated code to process the elements of vectors v1 and v2
   is right in the function that does it instead of being defined
   somewhere else.
*/
template<typename ret, typename arg1, typename arg2>
struct binary_fn: public std::binary_function<ret, arg1, arg2> {
   virtual ret operator()(const arg1&, const arg2&) const = 0 ;
} ;

/**
   \brief An adapter for local binary function objects.

   When we use STL algorithms such as for_each and transform, we usually
   have to define functions or function objects to process the individual
   elements of the container or sequence of interest. The problem with
   this is that the logic for processing a data sequence, which is,
   arguably, the main point of many functions, is removed from the point
   where the data of interest is actually meant to be handled. That is,
   data processing becomes distributed across many different small
   functions and classes, hampering code readability and maintainability.

   Boost.Lambda ameliorates the situation in many cases when the
   processing is simple. However, sometimes we want to be able to do
   something fairly complicated, which often requires defining a separate
   function or object.

   This class helps in these cases by defining a generic binary function
   object meant to be used in conjunction with the binary_fn class so
   that the code to process containers, etc., can be defined in local
   classes right near the call site of STL/generic algorithms. Here is
   some illustrative code showing how this class should be used:

   \code

      std::vector<type3>
      some_function(const std::vector<type1>& v1, const std::vector<type2>& v2)
      {
         struct transformer: public binary_fn<type3, type1, type2> {
            type3 operator()(const type1& t1, const type2& t2) const {
               return something_complicated(t1, t2) ;
            }
         } trans ;
         std::vector<type3> v3 ;
         std::transform(v1.begin(), v1.end(), v2.begin(),
                        std::back_inserter(v3),
                        local_binary_functor<type3, type1, type2>(func)) ;
         return v3 ;
      }

   \endcode

   Now, the complicated code to process the elements of vectors v1 and v2
   is right in the function that does it instead of being defined
   somewhere else.

   NOTE: One small point to keep in mind when using this adapter is that,
   since it holds a reference to a binary_fn object (so that the virtual
   function mechanism works properly and invokes the derived class's
   function call operator), you must create a local variable
   instantiating the local class derived from binary_fn. That is, you
   cannot create a temporary instance as is often done in conjunction
   with STL algorithms. In the above code, for example, you cannot use
   the following call to the transform algorithm:

   \code
      std::transform(v1.begin(), v1.end(), v2.begin(),
                     std::back_inserter(v3),
                     local_binary_functor<type3, type1, type1>(transformer()));
   \endcode

   This doesn't work because the compiler can get rid of the temporary
   object at its discretion so that by the time the call to
   local_binary_functor's constructor kicks in, there is no object
   available of which we can take a reference. Thus, it is required to
   create a local variable of type transformer (trans in the above sample
   code).
*/
template<typename ret, typename arg1, typename arg2>
class local_binary_functor {
   binary_fn<ret, arg1, arg2>& f ;
public:
   local_binary_functor(binary_fn<ret, arg1, arg2>& fn): f(fn) {}
   ret operator()(const arg1& a, const arg2& b) {return f(a, b);}
} ;

/**
   \brief  Helper function to return local binary function object adapters.
   \param  f Reference to a binary_fn derived object.
   \return A local_binary_functor adapter that can be passed to STL algorithms.

   This function simplifies the call site syntax associated with using
   the binary_fn and local_binary_functor classes by using template
   function parameter type deduction to reduce the amount of code needed
   to fully specify and utilize the local function object paradigm
   enabled by these classes.

   Thus, for instance, the sample code shown for the binary_fn class
   would become:

   \code

      std::vector<type3>
      some_function(const std::vector<type1>& v1, const std::vector<type2>& v2)
      {
         struct something_complicated: public binary_fn<type3, type1, type2> {
            type3 operator()(const type1& t1, const type2& t2) const {
               return something_complicated(t1, t2) ;
            }
         } func ;
         std::vector<type3> v3 ;
         std::transform(v1.begin(), v1.end(), v2.begin(),
                        std::back_inserter(v3), local_fn(func)) ;
         return v3 ;
      }

   \endcode

   As we can see, with this function we don't have to specify the
   template types when creating an instance of local_binary_functor to
   pass to the transform algorithm.
*/
template<typename ret, typename arg1, typename arg2>
inline local_binary_functor<ret, arg1, arg2>
local_fn(binary_fn<ret, arg1, arg2>& f)
{
   return local_binary_functor<ret, arg1, arg2>(f) ;
}

//-----------------------------------------------------------------------

} // end of namespace encapsulating this file's definitions

#endif

/* So things look consistent in everyone's emacs... */
/* Local Variables: */
/* indent-tabs-mode: nil */
/* End: */
